﻿// ***********************************************************************************************************************************************************
// * Copyright (c) 2008 Unit Software                                                                                                                        *
// *                                                                                                                                                         *
// * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),      *
// * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,      *
// * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:              *
// *                                                                                                                                                         *
// * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.                          *
// *                                                                                                                                                         *
// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,     *
// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      *
// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS    *
// * IN THE SOFTWARE.                                                                                                                                        *
// ***********************************************************************************************************************************************************
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Linq;
using System.Runtime.Serialization;
using UnitSoftware.LINQ2SQLExtensions.Exceptions;

namespace UnitSoftware.LINQ2SQLExtensions
{
    [DataContract]
    public abstract class Entity
    {
        #region Public 

        public virtual Type TableType
        {
            get { return GetType(); }
        }

        public int PrimaryKey
        {
            get
            {
                object[] attrs;
                foreach (var info in GetType().GetProperties())
                    if ((attrs = info.GetCustomAttributes(typeof (ColumnAttribute), true)).Length > 0 &&
                        ((ColumnAttribute) attrs[0]).IsPrimaryKey)
                        return (int) info.GetValue(this, new object[] {});

                throw new NoPrimaryKeyException(this);
            }
        }

        public virtual bool IsVirgin
        {
            get { return PrimaryKey == 0; }
        }

        public event PropertyChangedEventHandler OnPropertyChanged;

        public Entity GetOnContext(DataContext context)
        {
            var entities = new List<Entity>();

            foreach (Entity entity in context.GetTable(TableType))
                entities.Add(entity);

            return entities.SingleOrDefault(e => e.PrimaryKey == PrimaryKey);
        }

        #endregion

        #region Protected

        protected Entity()
        {
            ((INotifyPropertyChanged) this).PropertyChanged += Entity_PropertyChanged;
        }

        #endregion

        #region Internal

        internal Guid TransientGuid
        {
            get { return _transientGuid; }
        }

        #endregion

        #region Private

        private readonly Guid _transientGuid = Guid.NewGuid();

        private void Entity_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (OnPropertyChanged != null)
                OnPropertyChanged(this, e);
        }

        #endregion
    }
}